home *** CD-ROM | disk | FTP | other *** search
/ Netscape Plug-Ins Developer's Kit / Netscape_Plug-Ins_Developers_Kit.iso / CGIPERL / MACPERL / MSRCE418.HQX / Perl Source ƒ / MacPerl / MPFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-25  |  20.3 KB  |  937 lines

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPFile.c            -
  4. Author    :    Matthias Neeracher
  5.  
  6. A lot of this code is borrowed from 7Edit written by
  7. Apple Developer Support UK
  8.  
  9. Language    :    MPW C
  10.  
  11. $Log: MPFile.c,v $
  12. Revision 1.1  1994/02/27  23:00:47  neeri
  13. Initial revision
  14.  
  15. Revision 0.6  1993/09/17  00:00:00  neeri
  16. Runtime version
  17.  
  18. Revision 0.5  1993/08/28  00:00:00  neeri
  19. Handle multiple preference files
  20.  
  21. Revision 0.4  1993/08/17  00:00:00  neeri
  22. Enable Save
  23.  
  24. Revision 0.3  1993/08/13  00:00:00  neeri
  25. Write bounds rectangles
  26.  
  27. Revision 0.2  1993/05/30  00:00:00  neeri
  28. Support Console Windows
  29.  
  30. Revision 0.1  1993/05/29  00:00:00  neeri
  31. Compiles correctly
  32.  
  33. *********************************************************************/
  34.  
  35. #include <Errors.h>
  36. #include <Resources.h>
  37. #include <Desk.h>
  38. #include <PLStringFuncs.h>
  39. #include <AppleEvents.h>
  40. #include <AERegistry.h>
  41. #include <StandardFile.h>
  42. #include <TFileSpec.h>
  43. #include <Balloons.h>
  44.  
  45. #include "MPFile.h"
  46. #include "MPSave.h"
  47.  
  48. /**-----------------------------------------------------------------------
  49.         Name:             FileError
  50.         Purpose:        Puts up an error alert.
  51.     -----------------------------------------------------------------------**/
  52.  
  53.  
  54. #if !defined(powerc) && !defined(__powerc)
  55. #pragma segment File
  56. #endif
  57.  
  58. pascal void FileError(Str255 s, Str255 f)
  59. {
  60.     short    alertResult;
  61.  
  62.     SetCursor(&qd.arrow);
  63.     ParamText(s, f, (StringPtr) "\p", (StringPtr) "\p");
  64.      alertResult = Alert(ErrorAlert, nil);
  65. }
  66.  
  67. /**-----------------------------------------------------------------------
  68.         Name:             DoClose
  69.         Purpose:        Closes a window.
  70.     -----------------------------------------------------------------------**/
  71.  
  72. #if !defined(powerc) && !defined(__powerc)
  73. #pragma segment File
  74. #endif
  75.  
  76. pascal OSErr DoClose(WindowPtr aWindow, Boolean canInteract, DescType dialogAnswer)
  77. {
  78.      DPtr    aDocument;
  79.      short   alertResult;
  80.      Str255  theName;
  81.     OSErr   myErr;
  82.  
  83.     myErr = noErr;
  84.  
  85.      if (gWCount > 0) {
  86.         aDocument = DPtrFromWindowPtr(aWindow);
  87.  
  88.         if (aDocument->kind == kDocumentWindow) {
  89.             if (aDocument->dirty)
  90.                 if (canInteract && (dialogAnswer==kAEAsk)) {
  91.                     if (aDocument->u.reg.everSaved == false)
  92.                         GetWTitle(aWindow, theName); /* Pick it up as a script may have changed it */
  93.                     else
  94.                         PLstrcpy(theName, aDocument->theFileName);
  95.     
  96.                     ParamText(theName, (StringPtr) "\p", (StringPtr) "\p", (StringPtr) "\p");
  97.                     SetCursor(&qd.arrow);
  98.                     alertResult = Alert(SaveAlert, nil);
  99.                     switch (alertResult) {
  100.                     case aaSave:
  101.                         myErr = SaveAskingName(aDocument, canInteract);
  102.                         break;
  103.     
  104.                     case aaCancel:
  105.                         return userCanceledErr;
  106.     
  107.                     case aaDiscard:
  108.                         aDocument->dirty = false;
  109.                         break;
  110.                     }
  111.                 } else {
  112.                     if (dialogAnswer==kAEYes)
  113.                         myErr = SaveAskingName(aDocument, canInteract);
  114.                     else
  115.                         myErr = noErr; /* Don't save */
  116.                 }
  117.                 
  118.             if (!myErr) {
  119. #ifndef RUNTIME
  120.                 if (aDocument->kind == kDocumentWindow && aDocument->u.reg.numSections)
  121.                     DeRegisterAllSections(aDocument);
  122. #endif
  123.  
  124.                 CloseMyWindow(aWindow);
  125.             }
  126.         } else if (aDocument->u.cons.selected) {
  127.             if (!gQuitting) {
  128.                 SysBeep(0);
  129.     
  130.                 return userCanceledErr;
  131.             }
  132.         } else 
  133.             SaveConsole(aDocument);
  134.     } else
  135.         myErr = errAEIllegalIndex;
  136.  
  137.     return myErr;
  138. }
  139.  
  140. #if !defined(powerc) && !defined(__powerc)
  141. #pragma segment File
  142. #endif
  143.  
  144. //  DoQuit
  145. //  saveOpt - one of kAEAsk,kAEYes,kAENo
  146. //  if kAEYes or kAEAsk then AEInteactWithUser should have been called
  147. //  before DoQuit. Assumes that it can interact if it needs to.
  148.  
  149. pascal void DoQuit(DescType saveOpt)
  150. {
  151.     WindowPeek    aWindow;
  152.     WindowPeek    nextWindow;
  153.     short            theKind;
  154.  
  155.     if (gRunningPerl && (Alert(AbortAlert, nil) == 2))
  156.         return;
  157.         
  158.     gQuitting = true;
  159.  
  160.     for (aWindow = (WindowPeek) FrontWindow(); aWindow; aWindow = nextWindow) {
  161.         nextWindow = aWindow->nextWindow;
  162.         if (Ours((WindowPtr) aWindow)) {
  163.             if (DoClose((WindowPtr) aWindow, true, saveOpt)) {
  164.                 gQuitting = false;
  165.                 
  166.                 return;
  167.             }
  168.         } else {
  169.             theKind = aWindow->windowKind;
  170.             if (theKind < 0)
  171.                 CloseDeskAcc(theKind);
  172.         }
  173.     }
  174. }
  175.  
  176. #ifndef RUNTIME
  177. pascal Boolean GetFileFilter(CInfoPBPtr pb)
  178. {
  179.     switch (GetDocTypeFromInfo(pb)) {
  180.     case kPreferenceDoc:
  181.         /* We don't want preference files here. Maybe we should */
  182.     case kUnknownDoc:
  183.         return true;
  184.     default:
  185.         return false;
  186.     }
  187. }
  188.  
  189. #if USESROUTINEDESCRIPTORS
  190. RoutineDescriptor    uGetFileFilter = 
  191.         BUILD_ROUTINE_DESCRIPTOR(uppFileFilterProcInfo, GetFileFilter);
  192. #else
  193. #define uGetFileFilter *(FileFilterUPP)&GetFileFilter
  194. #endif
  195.  
  196. #else
  197. pascal Boolean GetFileFilter(ParmBlkPtr info)
  198. {
  199.     switch (info->fileParam.ioFlFndrInfo.fdType) {
  200.     case 'APPL':
  201.         switch (info->fileParam.ioFlFndrInfo.fdCreator) {
  202.         case MPRtSig:
  203.             return false;
  204.         case MPAppSig:
  205.             return !info->fileParam.ioFlLgLen;
  206.         default:
  207.             return true;
  208.         }
  209.     case 'TEXT':
  210.         return false;
  211.     default:
  212.         return true;
  213.     }
  214. }
  215. #endif
  216.  
  217. pascal OSErr GetFile(FSSpec *theFSSpec)
  218. {
  219. #ifndef RUNTIME
  220.     StandardFileReply  reply;
  221.  
  222.     BuildSEList();
  223.     
  224.     StandardGetFile(&uGetFileFilter, MacPerlFileTypeCount, MacPerlFileTypes, &reply);
  225.  
  226.     if (reply.sfGood) {
  227.         *theFSSpec = reply.sfFile;
  228.         return noErr;
  229.     } else
  230.         return userCanceledErr;
  231.         
  232. #else
  233.  
  234.     SFTypeList     myTypes = {'TEXT', 'APPL'};
  235.     SFReply          reply;
  236.     Point            where;
  237.  
  238.     where.h = where.v = 75;
  239.  
  240.     SFGetFile(
  241.         where, (StringPtr) "\p", 
  242.         (FileFilterUPP) GetFileFilter, 2, myTypes, 
  243.         (DlgHookProcPtr) nil,
  244.         &reply);
  245.  
  246.     if (reply.good)
  247.         return WD2FSSpec(reply.vRefNum, reply.fName, theFSSpec);
  248.     else
  249.         return userCanceledErr;
  250.         
  251. #endif
  252. }
  253.  
  254. #if !defined(powerc) && !defined(__powerc)
  255. #pragma segment File
  256. #endif
  257.  
  258. pascal OSErr DoCreate(FSSpec theSpec)
  259. {
  260.     OSErr err;
  261.  
  262. #ifndef RUNTIME
  263.     err = FSpCreate(&theSpec, MPAppSig, 'TEXT', smSystemScript);
  264. #else
  265.     err = HCreate(theSpec.vRefNum, theSpec.parID, theSpec.name, MPAppSig, 'TEXT');
  266. #endif
  267.  
  268.     if (!err)
  269.         HCreateResFile(theSpec.vRefNum, theSpec.parID, theSpec.name);
  270.     else
  271.         ShowError((StringPtr) "\pCreating", err);
  272.  
  273.     return err;
  274. }
  275.  
  276. pascal OSErr SaveConsole(DPtr doc)
  277. {
  278.     OSErr            err;
  279.     short       resFile;
  280.     HHandle     theHHandle;
  281.     Str255        title;
  282.     Boolean        existing;
  283.     
  284.     if (gPrefsFile) {
  285.         resFile    =    CurResFile();
  286.         UseResFile(gPrefsFile);
  287.         GetWTitle(doc->theWindow, title);
  288.         
  289.         if (theHHandle = (HHandle) Get1NamedResource('TFSS', title)) {
  290.             existing = true;
  291.         } else {
  292.             existing = false;
  293.             theHHandle = (HHandle)NewHandle(sizeof(HeaderRec));
  294.         }
  295.         
  296.         HLock((Handle)theHHandle);
  297.     
  298.         (*theHHandle)->theRect     = doc->theWindow->portRect;
  299.         OffsetRect(
  300.             &(*theHHandle)->theRect,
  301.             -doc->theWindow->portBits.bounds.left,
  302.             -doc->theWindow->portBits.bounds.top);
  303.             
  304.         GetFontName((*(doc->theText))->txFont, (StringPtr) &(*theHHandle)->theFont);
  305.         
  306.         (*theHHandle)->theSize     = (*(doc->theText))->txSize;
  307.         (*theHHandle)->lastID      = 0;
  308.         (*theHHandle)->numSections = 0;
  309.     
  310.         HUnlock((Handle)theHHandle);
  311.     
  312.         if (existing) {
  313.             ChangedResource((Handle) theHHandle);
  314.             WriteResource((Handle) theHHandle);
  315.             UpdateResFile(gPrefsFile);
  316.         } else {
  317.             AddResource((Handle)theHHandle, 'TFSS', Unique1ID('TFSS'), title);
  318.         }
  319.         
  320.         err = ResError();
  321.         
  322.         UseResFile(resFile);
  323.     }
  324.     
  325.     if (doc->u.cons.cookie) {
  326.         /* We might need this window again. */
  327.         DoHideWindow(doc->theWindow);
  328.         TESetSelect(0, 32767, doc->theText);
  329.         TEDelete(doc->theText);
  330.     
  331.         if (doc->u.cons.fence < 32767)
  332.             doc->u.cons.fence    = 0;
  333.     } else /* Done with this window */
  334.         CloseMyWindow(doc->theWindow);
  335.     
  336.     return err;
  337.  
  338. pascal void ApplySettings(DPtr doc, HPtr settings)
  339. {
  340.     short        fNum;
  341.     FontInfo    info;
  342.     Rect        bounds;
  343.     
  344.     GetFNum(settings->theFont, &fNum);
  345.     SetPort(doc->theWindow);
  346.     TextFont(fNum);
  347.     TextSize(settings->theSize);
  348.     GetFontInfo(&info);
  349.     
  350.     (*doc->theText)->txFont         = fNum;
  351.     (*doc->theText)->txSize         = settings->theSize;
  352.     (*doc->theText)->lineHeight    = info.ascent+info.descent+info.leading;
  353.     (*doc->theText)->fontAscent    = info.ascent;
  354.     
  355.     bounds.top                            = settings->theRect.top - 13;
  356.     bounds.left                            = settings->theRect.left + 5;
  357.     bounds.bottom                        = settings->theRect.top  - 5;
  358.     bounds.right                        = settings->theRect.right - 5;
  359.     
  360.     if (settings->theRect.right > settings->theRect.left + 50 &&
  361.         settings->theRect.bottom > settings->theRect.top  + 50 &&
  362.         RectInRgn(&bounds, GetGrayRgn())
  363.     ) {
  364.         MoveWindow(doc->theWindow, settings->theRect.left, settings->theRect.top, false);
  365.         SizeWindow(
  366.             doc->theWindow,
  367.             settings->theRect.right - settings->theRect.left,
  368.             settings->theRect.bottom - settings->theRect.top,
  369.             false);
  370.     }
  371.         
  372.     ResizeWindow(doc);
  373. }
  374.  
  375. pascal void RestoreConsole(DPtr doc)
  376. {
  377.     short       resFile;
  378.     HHandle     theHHandle;
  379.     Str255        title;
  380.     
  381.     if (!gPrefsFile)
  382.         return;
  383.         
  384.     resFile    =    CurResFile();
  385.     UseResFile(gPrefsFile);
  386.     GetWTitle(doc->theWindow, title);
  387.     
  388.     if (theHHandle = (HHandle) Get1NamedResource('TFSS', title)) {
  389.          HLock((Handle)theHHandle);
  390.         
  391.         ApplySettings(doc, *theHHandle);
  392.         
  393.         HUnlock((Handle)theHHandle);
  394.     }
  395.     
  396.     UseResFile(resFile);
  397. }
  398.  
  399.  
  400. /** -----------------------------------------------------------------------
  401.         Name:         GetFileContents
  402.         Purpose:        Opens the document specified by theFSSpec and puts
  403.                         the contents into theDocument.
  404.      -----------------------------------------------------------------------**/
  405.  
  406. #if !defined(powerc) && !defined(__powerc)
  407. #pragma segment File
  408. #endif
  409.  
  410. pascal OSErr GetFileContents(FSSpec spec, DPtr theDocument)
  411. {
  412.     long            theSize;
  413.     short            oldRes;
  414.     short            resFile;
  415.     short            refNum;
  416.     OSErr            err;
  417.     HHandle        aHandle;
  418.     Handle        gHandle;
  419.  
  420.     oldRes    =    CurResFile();
  421.     resFile     =    HOpenResFile(spec.vRefNum, spec.parID, spec.name, fsRdPerm);
  422.     
  423.     theDocument->u.reg.everLoaded = true;
  424.     theDocument->u.reg.origFSSpec = spec;
  425.     
  426.     if (theDocument->inDataFork) {
  427. #ifndef RUNTIME
  428.         if (err = HOpenDF(spec.vRefNum, spec.parID, spec.name, fsRdPerm, &refNum)) {
  429.             ShowError((StringPtr) "\pread file - HOpenDF", err);
  430. #else
  431.         if (err = HOpen(spec.vRefNum, spec.parID, spec.name, fsRdPerm, &refNum)) {
  432.             ShowError((StringPtr) "\pread file - HOpen", err);
  433. #endif
  434.             refNum = 0;
  435.             
  436.             goto giveUp;
  437.         }
  438.     
  439.         if (err = GetEOF(refNum, &theSize))
  440.             goto giveUp;
  441.  
  442.           gHandle = NewHandle(theSize);
  443.  
  444.         HLock(gHandle);
  445.         if (err = FSRead(refNum, &theSize, *gHandle))
  446.             return err;
  447.         HUnlock(gHandle);
  448.         FSClose(refNum);
  449.     } else {
  450.         gHandle    =    Get1NamedResource('TEXT', (StringPtr) "\p!");
  451.         
  452.         if (gHandle) 
  453.             DetachResource(gHandle);
  454.         else {
  455.             err = ResError();
  456.             
  457.             goto giveUp;
  458.         }
  459.     }
  460.  
  461.     theDocument->u.reg.numSections = 0;
  462.  
  463.     if (resFile != -1) {
  464.         aHandle = nil;
  465.  
  466.         if (Count1Resources('TFSS'))
  467.             aHandle = (HHandle)Get1Resource('TFSS', 255);
  468.  
  469.         if (aHandle) {
  470.             theDocument->u.reg.numSections = (*aHandle)->numSections;
  471.             
  472.             HLock((Handle) aHandle);
  473.             ApplySettings(theDocument, *aHandle);
  474.         }
  475.  
  476.         /*
  477.             If there is a print record saved, ditch the old one
  478.             created by new document and fill this one in
  479.         */
  480.         if (Count1Resources('TFSP')) {
  481.             if (theDocument->thePrintSetup)
  482.                 DisposHandle((Handle)theDocument->thePrintSetup);
  483.  
  484.             theDocument->thePrintSetup = (THPrint)Get1Resource('TFSP', 255);
  485.               HandToHand((Handle *)&theDocument->thePrintSetup);
  486.  
  487.             PrValidate(theDocument->thePrintSetup);
  488.         }
  489.  
  490. #ifndef RUNTIME
  491.         if (theDocument->u.reg.numSections) {
  492.             ReadSectionRecords(theDocument);
  493.             ReadAllSectionResources(theDocument);
  494.         }
  495. #else
  496.         theDocument->u.reg.numSections    =    0;
  497. #endif
  498.  
  499.         CloseResFile(resFile);
  500.  
  501.         if (err = ResError()) {
  502.             ShowError((StringPtr) "\pread file- CloseResFile", err);
  503.             return err;
  504.         }
  505.     }
  506.  
  507.     HLock(gHandle);
  508.     if (GetHandleSize(gHandle) > 32000) {
  509.         PtrToXHand(
  510.             *gHandle, 
  511.             (*theDocument->theText)->hText, 
  512.             GetHandleSize(gHandle));
  513.         
  514.         err = elvisErr;
  515.     } else
  516.         TESetText(*gHandle, GetHandleSize(gHandle), theDocument->theText);
  517.     DisposHandle(gHandle);
  518.  
  519.     if (err == fnfErr)
  520.         return noErr;
  521.     else
  522.           return err;
  523.  
  524. giveUp:    
  525.     if (refNum)
  526.         FSClose(refNum);
  527.         
  528.     if (resFile > -1)
  529.         CloseResFile(resFile);
  530.     
  531.     UseResFile(oldRes);
  532.     
  533.     return err;
  534. } /* GetFileContents */
  535.  
  536.  
  537. #if !defined(powerc) && !defined(__powerc)
  538. #pragma segment File
  539. #endif
  540.  
  541. pascal OSErr SaveAskingName(DPtr aDocument, Boolean canInteract)
  542. {
  543.     OSErr    myErr;
  544.  
  545.     if (aDocument->kind != kDocumentWindow || !aDocument->u.reg.everSaved) {
  546.  
  547.         if (canInteract) {
  548.             if (myErr = GetFileNameToSaveAs(aDocument))
  549.                 return myErr;
  550.  
  551.             if (myErr = SaveWithoutTemp(aDocument, aDocument->theFSSpec))
  552.                 return myErr;            
  553. #ifndef RUNTIME
  554.             AssocAllSections(aDocument);
  555. #endif
  556.  
  557.             return noErr;
  558.         } else
  559.             return errAENoUserInteraction;
  560.  
  561.     } else
  562.         return SaveUsingTemp(aDocument);
  563. }
  564.  
  565. #if !defined(powerc) && !defined(__powerc)
  566. #pragma segment File
  567. #endif
  568.  
  569. pascal OSErr SaveUsingTemp(DPtr theDocument)
  570. {
  571.     Str255    tempName;
  572.     OSErr        err;
  573.     FSSpec    tempFSSpec;
  574.  
  575.     /*save the file to disk using a temporary file*/
  576.     /*this is the recommended way of doing things*/
  577.     /*first write out the file to disk using a temporary filename*/
  578.     /*if it is sucessfully written, exchange the temporary file with the last one saved*/
  579.     /*then delete the temporary file- so if anything goes wrong, the original version is still there*/
  580.     /*first generate the temporary filename*/
  581.  
  582.     GetTempFSSpec(theDocument, &tempFSSpec);
  583.  
  584.     if (err = DoCreate(tempFSSpec))
  585.         return err;
  586.  
  587.     if (err = DoSave(theDocument, tempFSSpec))
  588.         return err;
  589.     
  590. #ifndef RUNTIME
  591.     if (err = FSpExchangeFiles(&tempFSSpec, &theDocument->theFSSpec))
  592.         return err;
  593.     
  594.     /*we've exchanged the files, now delete the temporary one*/
  595.  
  596.     FSpDelete(&tempFSSpec);
  597. #else
  598.     err = FSpSmartMove(&tempFSSpec, &theDocument->theFSSpec);
  599. #endif
  600.     
  601.     if (!err && theDocument->kind == kDocumentWindow) {
  602.         theDocument->dirty                 = false;
  603.         theDocument->u.reg.everSaved     = true;
  604.         theDocument->u.reg.origFSSpec = theDocument->theFSSpec;
  605.     }
  606.  
  607.     return err;
  608. }
  609.  
  610. pascal OSErr SaveWithoutTemp(DPtr theDocument, FSSpec spec)
  611. {
  612.     OSErr        err;
  613.     
  614.     if (err = DoSave(theDocument, spec))
  615.         return err;
  616.  
  617.     if (theDocument->kind == kDocumentWindow) {
  618.         theDocument->dirty                 = false;
  619.         theDocument->u.reg.everSaved     = true;
  620.         theDocument->u.reg.origFSSpec = theDocument->theFSSpec = spec;
  621.                 
  622.         SetWTitle(theDocument->theWindow, theDocument->theFSSpec.name);
  623.     }
  624.     
  625.     return noErr;
  626. }
  627.  
  628. #if !defined(powerc) && !defined(__powerc)
  629. #pragma segment File
  630. #endif
  631.  
  632. pascal short SaveScriptHook(short item, DialogPtr dlg, void * params)
  633. {
  634.     short                kind;
  635.     ControlHandle    type;
  636.     MenuHandle        typeMenu;
  637.     Rect                r;
  638.     DPtr                doc = (DPtr) params;
  639.     
  640.     if (GetWRefCon(dlg) != 'stdf')
  641.         return item;
  642.         
  643.     switch (item) {
  644.     case sfHookFirstCall:
  645.         GetDItem(dlg, ssd_Type, &kind, (Handle *) &type, &r);
  646.         typeMenu = (*(PopupPrivateDataHandle)(*type)->contrlData)->mHandle;
  647.         
  648.         AddExtensionsToMenu(typeMenu);
  649.         SetControlMaximum(type, CountMItems(typeMenu));
  650.         SetCtlValue(type, Type2Menu(doc->type));
  651.         
  652.         return sfHookFirstCall;
  653.     case ssd_Type:
  654.         GetDItem(dlg, item, &kind, (Handle *) &type, &r);
  655.         
  656.         doc->type = (DocType) Menu2Type(GetCtlValue(type));
  657.         
  658.         return sfHookNullEvent;
  659.     default:
  660.         return item;
  661.     }
  662. }
  663.  
  664. #if USESROUTINEDESCRIPTORS
  665. RoutineDescriptor    uSaveScriptHook = 
  666.         BUILD_ROUTINE_DESCRIPTOR(uppDlgHookYDProcInfo, SaveScriptHook);
  667. #else
  668. #define uSaveScriptHook *(DlgHookYDUPP)&SaveScriptHook
  669. #endif
  670.  
  671. /*
  672.     Fills in the document record with the user chosen destination
  673. */
  674.  
  675. pascal OSErr GetFileNameToSaveAs(DPtr theDocument)
  676. {
  677. #ifndef RUNTIME
  678.     OSErr                    err;
  679.     StandardFileReply    reply;
  680.     Str255            suggestName;
  681.     Point                    where;
  682.     
  683.     where.h = where.v = -1;
  684.  
  685.     GetWTitle(theDocument->theWindow, suggestName);
  686.  
  687. #ifndef RUNTIME
  688.     HMSetDialogResID(SaveScriptDialog);
  689. #endif
  690.     CustomPutFile(
  691.         (StringPtr) "\pSave Document As:", suggestName, &reply,
  692.         SaveScriptDialog,
  693.         where,
  694.         &uSaveScriptHook,
  695.         (ModalFilterYDUPP) nil,
  696.         nil,
  697.         (ActivateYDUPP) nil,
  698.         theDocument);
  699. #ifndef RUNTIME
  700.     HMSetDialogResID(-1);
  701. #endif
  702.  
  703.     if (reply.sfGood)
  704.         switch (err = FSpDelete(&reply.sfFile)) {
  705.         case noErr:
  706.         case fnfErr:
  707.             theDocument->theFSSpec = reply.sfFile;
  708.             PLstrcpy(theDocument->theFileName, reply.sfFile.name);
  709.  
  710.             return noErr;
  711.         default:
  712.             return err;
  713.         }
  714.     else
  715.         return userCanceledErr;
  716. #else
  717.     OSErr        err;
  718.     SFReply    reply;
  719.     Str255   suggestName;
  720.     Point        where;
  721.  
  722.     where.h = where.v = 75;
  723.     
  724.     GetWTitle(theDocument->theWindow, suggestName);
  725.  
  726.     SFPutFile(
  727.         where, (StringPtr) "\pSave Document As:", 
  728.         suggestName, (DlgHookProcPtr) nil,
  729.         &reply);
  730.     
  731.     if (reply.good) {
  732.         FSSpec    spec;
  733.         
  734.         if (err = WD2FSSpec(reply.vRefNum, reply.fName, &spec))
  735.             return err;
  736.         switch (err = HDelete(spec.vRefNum, spec.parID, spec.name)) {
  737.         case noErr:
  738.         case fnfErr:
  739.             theDocument->theFSSpec = spec;
  740.             PLstrcpy(theDocument->theFileName, spec.name);
  741.  
  742.             return noErr;
  743.         default:
  744.             return err;
  745.         }
  746.     } else
  747.         return userCanceledErr;
  748. #endif
  749. } /* GetFileNameToSaveAs */
  750.  
  751. #if !defined(powerc) && !defined(__powerc)
  752. #pragma segment File
  753. #endif
  754.  
  755. pascal DPtr MakeOldDoc(FSSpec aFSSpec, DocType type)
  756. {
  757.     DPtr          theDocument;
  758.     
  759.     theDocument = NewDocument(true, kDocumentWindow);
  760.  
  761.     SetWTitle(theDocument->theWindow, aFSSpec.name);
  762.  
  763.     SetPort(theDocument->theWindow);
  764.  
  765.     theDocument->theFSSpec   = aFSSpec;
  766.  
  767.     PLstrcpy(theDocument->theFileName, aFSSpec.name);
  768.  
  769.     theDocument->dirty               = false;
  770.     theDocument->inDataFork            = type == kPlainTextDoc || type == kOldRuntime6Doc;
  771.     
  772. #ifndef RUNTIME
  773.     /* We *can* open documents created by unknown save extensions, but we can't
  774.        save them again 
  775.     */
  776.     if (CanSaveAs(type)) {
  777.         theDocument->type                 = type;
  778.         theDocument->u.reg.everSaved    = true;
  779.     } else {
  780.         theDocument->type                    = (type == kOldRuntime6Doc) ? kRuntime6Doc : kPlainTextDoc;
  781.         theDocument->u.reg.everSaved    = false;
  782.     }
  783. #else
  784.     theDocument->type                    = kPlainTextDoc;
  785.     theDocument->u.reg.everSaved    = (type == kPlainTextDoc);
  786. #endif
  787.  
  788.     return theDocument;
  789. }
  790.  
  791. pascal OSErr OpenOld(FSSpec aFSSpec, DocType type)
  792. {
  793.     DPtr          theDocument;
  794.     OSErr         fileErr;
  795.     WindowPtr    win;
  796.  
  797.     if (win = AlreadyOpen(&aFSSpec, nil)) {
  798.         SelectWindow(win);
  799.         
  800.         return noErr;
  801.     }
  802.     
  803.     theDocument    =    MakeOldDoc(aFSSpec, type);
  804.     
  805.     fileErr = GetFileContents(aFSSpec, theDocument);
  806.  
  807.     if (!fileErr) {
  808.         ResizeWindow(theDocument);
  809.         DoShowWindow(theDocument->theWindow);
  810.     } else {
  811.         if (fileErr == elvisErr) {
  812.             theDocument->u.reg.everSaved    = false;
  813. #ifdef RUNTIME
  814.             if (AEInteractWithUser(kAEDefaultTimeout, nil, nil))
  815. #endif
  816.                 if (Alert(ElvisAlert, nil) == 1)
  817.                     SaveAskingName(theDocument, true);
  818.         } else
  819.             FileError((StringPtr) "\pError Opening ", aFSSpec.name);
  820.         
  821.         CloseMyWindow(theDocument->theWindow);
  822.     }
  823.  
  824.     return fileErr;
  825. } /* OpenOld */
  826.  
  827. pascal OSErr File2File(FSSpec aFSSpec, DocType type, FSSpec toFSSpec, DocType newtype)
  828. {
  829.     DPtr          theDocument;
  830.     OSErr         fileErr;
  831.  
  832.     theDocument    =    MakeOldDoc(aFSSpec, type);
  833.     
  834.     switch (fileErr = GetFileContents(aFSSpec, theDocument)) {
  835.     case elvisErr:
  836.         fileErr = noErr;
  837.         /* Fall through */
  838.     case noErr:
  839.         theDocument->type = newtype;
  840.         theDocument->u.reg.everSaved    = false;
  841.         if (SameFSSpec(&aFSSpec, &toFSSpec))
  842.             fileErr = SaveUsingTemp(theDocument);
  843.         else
  844.             fileErr = SaveWithoutTemp(theDocument, toFSSpec);
  845.         
  846.         /* Fall through */
  847.     default:
  848.         CloseMyWindow(theDocument->theWindow);
  849.     }
  850.  
  851.     return fileErr;
  852. } /* File2File */
  853.  
  854. pascal OSErr Handle2File(Handle text, FSSpec toFSSpec, DocType newtype)
  855. {
  856.     DPtr          theDocument;
  857.     OSErr         fileErr;
  858.  
  859.     theDocument = NewDocument(true, kDocumentWindow);
  860.     
  861.     HLock(text);
  862.     PtrToXHand(*text, (*theDocument->theText)->hText, GetHandleSize(text));
  863.     HUnlock(text);
  864.     
  865.     theDocument->u.reg.everSaved    = false;
  866.     theDocument->type                 = newtype;
  867.  
  868.     fileErr = SaveWithoutTemp(theDocument, toFSSpec);
  869.     
  870.     CloseMyWindow(theDocument->theWindow);
  871.  
  872.     return fileErr;
  873. } /* Handle2File */
  874.  
  875. pascal DocType GetDocTypeFromFile(short vRefNum, long dirID, StringPtr name)
  876. {
  877.     short            resFile;
  878.     short            nuFile;
  879.     OSType    **    rtType;
  880.     DocType        type    =    kUnknownDoc;
  881.     
  882.     resFile    = CurResFile();
  883.     nuFile    = HOpenResFile(vRefNum, dirID, name, fsRdPerm);
  884.     
  885.     if (nuFile != -1) {
  886.         if (rtType = (OSType **) Get1Resource('MrPL', 128))
  887.             type = **(DocType **) rtType;
  888.             
  889.         CloseResFile(nuFile);
  890.     }
  891.     UseResFile(resFile);
  892.     
  893.     return type;
  894. }
  895.  
  896. pascal DocType GetDocTypeFromInfo(CInfoPBPtr info)
  897. {
  898.     DocType        type    =    kUnknownDoc;
  899.     
  900.     switch (info->hFileInfo.ioFlFndrInfo.fdType) {
  901.     case 'APPL':
  902.         if (info->hFileInfo.ioFlFndrInfo.fdCreator == MPAppSig) 
  903.             /* A heuristic to separate old runtimes from PowerPC executables */
  904.             if (info->hFileInfo.ioFlLgLen && info->hFileInfo.ioFlLgLen < 100000)
  905.                 return kOldRuntime6Doc; 
  906.         
  907.         break;
  908.     case 'TEXT':
  909.         return kPlainTextDoc;
  910.     case 'pref':
  911.         switch (info->hFileInfo.ioFlFndrInfo.fdCreator) {
  912.         case MPAppSig:
  913.         case MPRtSig:
  914.             return kPreferenceDoc;
  915.         }
  916.         break;
  917.     default:
  918.         break;
  919.     }
  920.     
  921.     /* Ultimately, with save extensions, every file could be ours */
  922.     return GetDocTypeFromFile(
  923.         info->hFileInfo.ioVRefNum, 
  924.         info->hFileInfo.ioFlParID, 
  925.         info->hFileInfo.ioNamePtr);;
  926. }
  927.  
  928. pascal DocType GetDocType(FSSpec * spec)
  929. {
  930.     CInfoPBRec    info;
  931.  
  932.     if (FSpCatInfo(spec, &info))
  933.         return kUnknownDoc;
  934.     else
  935.         return GetDocTypeFromInfo(&info);
  936. }